#pragma once
#include <iostream>
#include <queue>
#include <thread>
#include <functional>
#include <mutex>
#include <vector>
#include <unistd.h>
#include <condition_variable>

using namespace std;
using namespace placeholders;

#define numdefault 3

template <class T>
class thread_pool
{
    thread_pool(const thread_pool&)=delete;
    thread_pool operator=(const thread_pool&)=delete;

public:
    static thread_pool* get_instance()  // 单例
    {
        if(_instance==nullptr)
            _instance = new thread_pool();
        return _instance;
    }
    void task_execution(const string &args) // 多个线程开始任务执行
    {
        while (1)
        {
            T t;//调用默认构造
            {
                //共享代码段
                unique_lock<mutex> ul(_mtx);
                while (_qt.empty()) // 无任务就等待
                {
                    cond.wait(ul); // 等待期间会解锁,多线程会再等待队列中阻塞，等待成功会上锁
                }
                t = _qt.front();
                _qt.pop();
            }
            // 处理任务
            cout<<args<<": ";
            t();
            sleep(1);
        }
    }

    void push(const T &t)//传任务
    {
        unique_lock<mutex> ul(_mtx);
        _qt.push(t);
        cond.notify_one();//有任务则条件满足
    }

    ~thread_pool()//
    {
        for (int i = 0; i < _num; i++) // C++thread使用线程不join的话程序会崩溃
        {
            _vt[i].join();
        }
    }

private:
    thread_pool(int num = numdefault)//构造函数私有
        : _num(num), _vt(num)
    {

        for (int i = 0; i < _num; i++)
        {
            string name = "thread_";
            name += to_string(i + 1);
            // 移动赋值，线程不支持左值拷贝
            // _vt[i] = thread(&thread_pool<T>::task_execution, this, name); // 成员函数默认第一个参数是this指针，所以要显式传参
            _vt[i] = thread(bind(&thread_pool<T>::task_execution, this,_1), name);//bind其实与function功能一样，不过可以提前确定参数
        }
    }
    int _num;           // 线程数目
    queue<T> _qt;       // 任务管理
    vector<thread> _vt; // 管理线程

    mutex _mtx;              // 锁
    condition_variable cond; // 条件变量，任务为空等待
    static thread_pool* _instance;
};
template<class T>
thread_pool<T>* thread_pool<T>::_instance = nullptr;